#include <ctype.h>
#include <string.h>
#include <stdbool.h>
#include "lexical.h"
#include "error.h"
#include "parser.h"


void next_token(void);
bool match(symbol_e need);
void syntax_analyse(void);
void program(void);
void subprogram(void);
symbol_e type(void);
static symbol_e get_op(void);
static void get_id(char *name);
void decl(bool is_ext, symbol_e my_type, int scope);
void fun_body(int scope, const char *name);
void var_decl_tail(bool is_ext, symbol_e my_type, bool is_ptr,
                   const char *name);
int arr_len(const char *name);
void literal(void);
void primary_expr(void);
void arglist(void);
void arg(void);
void realarg(void);
void *get_fun_realarg(void);
void post_expr(void);
void unary_expr(void);
void mul_tail(void);
void mul_expr(void);
void add_tail(void);
void add_expr(void);
void relation_tail(void);
void relation_expr(void);
void equ_tail(void);
void equ_expr(void);
void logical_and_tail(void);
void logical_and_expr(void);
void logical_or_tail(void);
void logical_or_expr(void);
void assign_tail(void);
void assign_expr(void);
void expr(void);
void ele(void);
void arr_init_list(void);
void var_init(int arr_len, bool is_ext, symbol_e my_type, bool is_ptr,
          const char *name);
void global_decl(void);
void fun_decl_tail(bool is_ext, symbol_e my_type, bool ptr, const char *name,
                   int scope);
void var_item(bool is_ext, symbol_e my_type);
void var_list(bool is_ext, symbol_e my_type);
void para_decl(void);
void para_item(void);
void para_list(void);
void elements(void);
void next_token(void);
void block(void);
void case_label(void);
void elements_tail(void);
void case_stat(void);
void switch_stat(void);
void else_stat(void);
void statement(void);
void while_stat(void);
void for_stat(void);
void do_while_stat(void);
void for_init(void);
void for_cond(void);
void for_iter(void);
void if_stat(void);

static symbol_e get_op(void)
{
    symbol_e op = token_g;
    next_token();
    return op;
}

static void get_id(char *name) 
{ 
	strncpy(name, token_id_g, MAX_ID_LEN); 
}


bool match(symbol_e need)
{
    if (TEST(need)) {
        next_token();
        return true;
    } else {
        return false;
    }
}

void next_token(void)
{
    get_token();
    while (token_g == COMMENT || token_g == INVALID) {
        get_token();
    }
}


void syntax_analyse(void)  // 语法分析的入口
{
    check_symbol_num();
    next_token(); // 预先读入
    program();
}

/*
    <program> -> <global_decl> <program> | ε
*/
void program(void)
{
    if (TEST(FILE_END)) { // 文件结束
        return;
    } else {
        global_decl();
        program(); // 递归
    }
}

/*
    <type> -> int | char | void
*/
symbol_e type(void)
{
    symbol_e my_type = INT; // 默认类型是 int

    if (TYPE_FIRST) {
        my_type = token_g; // 记录类型
        next_token();      // 读入下一个符号
    }
    else { 
        // 报错 follow(<type>) = {ident, mul}
        recovery(TEST(ID) OR(MUL), EXPECTED_TYPE, WARNING); 

        // 这是另外一种尝试，但是测试效果不理想，有时候会忽略大段的 token
        //recovery_until_type(TEST(ID) OR(MUL), EXPECTED_TYPE, ERROR);
        // next_token(); 
    }

    return my_type;
}

/*
    <global_decl> -> extern <type> <decl>
                   | <type> <decl>
*/
void global_decl(void)
{
    bool ext = match(EXTERN); 
    symbol_e my_type = type();
    decl(ext, my_type, SCOPE_GLOBAL);
}

// 为了代码复用， local_decl 也调用 decl, 但是参数不一样，最终影响 <fun_body>
void local_decl(void)
{
    bool ext = match(EXTERN); 
    symbol_e my_type = type();
    decl(ext, my_type, SCOPE_LOCAL);
}


/*
    不支持混合声明。这样写虽然符合语法，但是可读性不好。例如：
    int foo1(int a),foo2(char b);
    int m,n,foo3(void);
*/

/*
    <decl>  ->  mul ident <decl_tail>
             |  ident <decl_tail>
    <decl_tail> -> <var_decl_tail> | <fun_decl_tail>
	
*/
void decl(bool is_ext, symbol_e my_type, int scope)
{
    char name[MAX_ID_LEN + 1] = {0};
    bool is_ptr = false;

    if (match(MUL)) { // 指针
        is_ptr = true;
    }

    if (TEST(ID)) {
        get_id(name);
        next_token();
    } else {
        // error: expected identifier
        recovery(DECL_HEAD_FOLLOW, EXPECTED_ID, ERROR); 
    }

    if (TEST(LPAREN)) {
        fun_decl_tail(is_ext, my_type, is_ptr, name, scope);
    } else {
        var_decl_tail(is_ext, my_type, is_ptr, name);
    }
}

/*
    <var_decl_tail> -> <arr_len> <var_init> <var_list>
    
*/
void var_decl_tail(bool is_ext, symbol_e my_type, bool is_ptr, const char *name)
{
    int len = arr_len(name);
    var_init(len, is_ext, my_type, is_ptr, name); 
    var_list(is_ext, my_type);
}


/*
	<arr_len> -> lbracket num rbracket 
	           | lbracket  rbracket 
	           | ε
*/
// 不支持变长数组！
int arr_len(const char *name)
{
    int len = NOT_ARR;
    if (match(LBRACKET)) { // 左方括号
        if (TEST(NUM)) { // 用 TEST 不用 match 是因为要获得数组长度
            len = token_num_g;            
            if (len <= 0) { // 因为不支持常量表达式，所以解析不了负数，TODO      
                syn_err(ARR_SIZE_NEGATIVE_OR_ZERO, ERROR, OTHER, name);
				len = ARR_SIZE_INVALID;
            }
			next_token();
        } else {
            if (match(RBRACKET)) { // []
                len = ARR_SIZE_UNKNOWN;
                return len;
            } else { // 例如 int a[x];
                syn_err(ARR_SIZE_NO_CONSTANT, ERROR, OTHER, name);
				len = ARR_SIZE_INVALID;
                // next_token();
                expr();// 比 next_token() 更健壮，可以处理类似 [x+3]
            }
        }
        if (!match(RBRACKET)) { // follow(<arr_len>) = {assign, comma, semico, rparen}
            recovery(TEST(COMMA)OR(SEMICO)OR(ASSIGN)OR(RPAREN), EXPECTED_RBRACKET,
                     ERROR); // expected ‘]’ before ‘;’
        }
    }
    return len; 
}

/*
    <var_init> 	-> assign <init_expr>  | ε
    <init_expr> -> <expr> | <arr_init_list>
 
*/
void var_init(int arr_len, bool is_ext, symbol_e my_type, bool is_ptr,
          const char *name)
{
    if (match(ASSIGN)) {
        if (arr_len != NOT_ARR) {
            arr_init_list();
        } else {
            expr();
        }
    }
}

/*
	<var_list> -> comma <var_item> <var_list> | semico

*/
void var_list(bool is_ext, symbol_e my_type)
{
    if (match(COMMA)) {
        var_item(is_ext, my_type);
        var_list(is_ext, my_type);
    } else if (match(SEMICO)) {
        return;
    } else {  // 出错了
        if (TEST(ID)OR(MUL)) { // 逗号丢失
            recovery(true, EXPECTED_COMMA, ERROR);
            var_item(is_ext, my_type); // 让解析回到正轨
            var_list(is_ext, my_type);
        } else { // expected ';'  
            recovery(VAR_LIST_FOLLOW, EXPECTED_SEMICOLON, ERROR);                  
        }
    }
}

/*
	<var_item> ->  ident <arr_len> <var_init> 
                |  mul ident <arr_len> <var_init>
*/
void var_item(bool is_ext, symbol_e my_type)
{
    char name[MAX_ID_LEN + 1] = {0};
    bool is_ptr = false;

    if (match(MUL)) { // 指针
        is_ptr = true;
    }

    if (TEST(ID)) {
        get_id(name);
        next_token();
    } else {
        recovery(TEST(SEMICO) OR(COMMA) OR(ASSIGN) OR(LBRACKET), EXPECTED_ID,
                 ERROR);
    }

    int len = arr_len(name);
    var_init(len, is_ext, my_type, is_ptr, name);
}



/*
 	<fun_decl_tail> -> lparen <para_decl> rparen <fun_body>
*/
void fun_decl_tail(bool is_ext, symbol_e my_type, bool ptr, const char *name,
                   int scope)
{
    match(LPAREN); // 调用它的函数已经检查了
    para_decl(); 
    if (!match(RPAREN))
        recovery(TEST(LBRACES) OR(SEMICO), EXPECTED_RPAREN,
                 ERROR); // error: expected ‘)’

    fun_body(scope, name);
}



/*
    <para_decl> -> void 
	            |  <para_item> <para_list>
				|  ε
*/
void para_decl(void)
{
	if(TEST(RPAREN)) // 例如 fun()
		return;
    if (match(VOID)) {
        if (TEST(RPAREN)) {
            return; // 例如 fun(void)
        } else {
            printf("变量类型不能是 void\n");  // 报语义错误,TODO         
        }
    }
    para_item();
    para_list();
}


/*
    <para_item> -> <type> ident <arr_len> 
	            |  <type> mul ident <arr_len>
*/
void para_item(void)
{
    char name[MAX_ID_LEN + 1] = {0};
    symbol_e my_type = type();
    bool is_ptr = false;

    if (match(MUL)) { //	指针
        is_ptr = true;
    }

    if (TEST(ID)) {
        get_id(name);
        next_token();
    } else {
        recovery(TEST(COMMA) OR(RPAREN) OR(LBRACKET), EXPECTED_ID, ERROR);
    }

    if (arr_len(name) != NOT_ARR) { // 参数是数组
        // 作为指针处理
    }
}

/*
    <para_list> -> comma <para_item> <para_list> |  ε

*/
void para_list(void)
{
    if (match(COMMA)) {
        para_item();
        para_list(); // 递归
    }
}

/*
    SCOPE_GLOBAL:    <fun_body> -> <block> | semico
    SCOPE_LOCAL:     <fun_body> ->  semico
*/

void fun_body(int scope, const char *name)
{
    if (scope == SCOPE_LOCAL) {
        if (!match(SEMICO)) {     // 错误处理 
            if (TEST(LBRACES)) { // forbids nested functions
                    syn_err(FORBIDS_NESTED_FUNCTIONS, ERROR, OTHER,
                        name); // todo 如何获得外层函数名？
               // 后续会以 <block> 处理                
            } else 
				recovery(LOCAL_DECL_FOLLOW, EXPECTED_SEMICOLON, ERROR);
        }
    }
    else {
        if (match(SEMICO)) { // 函数声明  

        } else { // 函数定义
            block();
        } 
    }
}


/*
	<elements> ->  <ele> <elements_tail>
	
*/
void elements(void)
{
    ele();
    elements_tail();
}

/*
    <arr_init_list> -> lbraces <elements> rbraces
                     |  STRING
*/

void arr_init_list(void)
{
    if(TEST(STRING)) {
        next_token();
        // 必须是字符数组才可以用字符串初始化
        return;
    }

    if (!match(LBRACES)) {
        recovery(EXPR_FIRST, EXPECTED_LBRACES, ERROR);
    }

    elements();

    if (!match(RBRACES)) {
        recovery(TEST(COMMA) OR(SEMICO), EXPECTED_RBRACES, ERROR);
    }
}


/*
	<elements_tail> -> comma <ele> <elements_tail> | ε
*/
void elements_tail(void)
{
    if (match(COMMA)) {
        ele();
        elements_tail();
    }
}

/*
    <ele> ->  <expr>
*/
void ele(void) 
{ 
	expr(); 
}

/*
    <expr> -> <assign_expr>
*/

void expr(void) 
{ 
    assign_expr(); 
}

/*
    <assign_expr>	->	<logical_or_expr> <assign_tail>
*/
void assign_expr(void)
{
    logical_or_expr();
    assign_tail();
}

/*
    <assign_tail>	->	assign  <assign_expr>
                     |  ε
*/
// 因为赋值运算符的结合性是从右到左，所以 <assign_expr> 是一个整体，要先求值
void assign_tail(void)
{
    if (match(ASSIGN)) {
        assign_expr();
    }
}

/*
    <logical_or_expr>  -> 	<logical_and_expr> <logical_or_tail>
*/
void logical_or_expr(void)
{
    logical_and_expr();
    logical_or_tail();
}

/*
    <logical_or_tail>  -> 	or <logical_and_expr> <logical_or_tail>
                        |    ε
*/
void logical_or_tail(void)
{
    if (match(OR)) {
        logical_and_expr();
        logical_or_tail();
    }
}

/*
    <logical_and_expr> -> <equ_expr> <logical_and_tail>

*/

void logical_and_expr(void)
{
    equ_expr();
    logical_and_tail();
}

/*
    <logical_and_tail> -> and <equ_expr> <logical_and_tail>
                        |  ε
*/
void logical_and_tail(void)
{
    if (match(AND)) {
        equ_expr();
        logical_and_tail();
    }
}

/*
    <equ_expr> -> <relation_expr> <equ_tail>
*/
void equ_expr(void)
{
    relation_expr();
    equ_tail();
}

/*
    <equ_tail> -> <equality_op> <relation_expr> <equ_tail>
                |  ε
    <equality_op> -> equ | nequ
*/

void equ_tail(void)
{
    if (TEST(EQU)OR(NEQU)) {
        next_token();
        relation_expr();
        equ_tail();
    }

}

/*
<relation_expr> ->  <add_expr> <relation_tail>
*/
void relation_expr(void)
{
    add_expr();
    relation_tail();
}

/*
    <relation_tail> ->  <relation_op> <add_expr> <relation_tail>
                     |   ε
    <relation_op> -> gt | ge | lt | le

*/

void relation_tail(void)
{
    if (TEST(GT) OR(GE) OR(LT) OR(LE)) {
        next_token();
        add_expr();
        relation_tail();
    }
}


/*
    <add_expr>   ->  <mul_expr>  <add_tail>
*/
void add_expr(void)
{
    mul_expr();
    add_tail();
}

/*
    <add_tail>   ->  <additive_op> <mul_expr>  <add_tail>
                  |  ε
    <additive_op> -> add | sub
*/
void add_tail(void)
{
    if (TEST(ADD)OR(SUB)) {
        next_token();
        mul_expr();       
        add_tail();
    }
}



/*
    <mul_expr>   ->  <unary_expr> <mul_tail>
*/
void mul_expr(void)
{
    unary_expr();
    mul_tail();
}

/*
    <mul_tail>   ->  <multi_op> <unary_expr> <mul_tail>
                  |  ε
    <multi_op> ->  mul | div | mod
*/
void mul_tail(void)
{
    if (TEST(MUL) OR(DIV) OR(MOD)) {
        next_token();
        unary_expr();
        mul_tail();
    }
}


/*
    <unary_expr>  -> <unary_op> <unary_expr> | <post_expr>
    <unary_op> -> incr | decr | add | sub | not | mul | lea | sizeof
*/

void unary_expr(void)
{
    if (TEST(INC) OR(DEC) OR(ADD) OR(SUB) OR(NOT) OR(MUL) OR(LEA) OR(SIZEOF)) {
        next_token();
        unary_expr();            // 递归
    }
    else
        post_expr();
}



/*
    <post_expr> -> <primary_expr> <R>
    <R> ->  <post_op> <R> | ε
    <post_op> -> incr | decr | lbracket <expr> rbracket | lparen <realarg> rparen
*/
void post_expr(void)
{
    primary_expr();
    while (1) {
        if (TEST(INC) OR(DEC)) {
            next_token();
        } else if (TEST(LBRACKET)) {
            next_token();
            expr();
            if (!match(RBRACKET))
                recovery(true, EXPECTED_RBRACKET, ERROR);  // 情况比较多，就不列举 follow 集了，报丢失
        } else if (TEST(LPAREN)) {
            next_token();
            realarg();
            if (!match(RPAREN))
                recovery(true, EXPECTED_RPAREN, ERROR); // 情况比较多，就不列举 follow 集了，报丢失
        } else {
            break;
        }
    }
}



/*
    <realarg>	->	<arg> <arglist> | ε
*/
void realarg(void) // TODO
{
    if (EXPR_FIRST) {
        arg();
        arglist();
    }
}

// <arg> -> <expr>
void arg(void)
{
    // 实际参数
    expr();
}

/*
    <arglist>	->	comma <arg> <arglist> | ε
*/
void arglist(void)
{
    if (match(COMMA)) {
        arg();
        arglist();
    }
}

/*
<primary_expr> ->  ident | lparen <expr> rparen | <literal>
*/
void primary_expr(void)
{

    if (TEST(ID)) { // 变量，数组名，函数名
        char name[MAX_ID_LEN + 1] = {0};
        get_id(name);
        next_token();
    } else if (match(LPAREN)) { // 括号表达式
        expr();
        if (!match(RPAREN)) { 
            recovery(true, EXPECTED_RPAREN, ERROR); // 情况比较多，就不列举 follow 集了，报丢失
        }
    } else { // 常量
        literal();
    }
}

/*
    <literal>	->	num | string | chara
*/
void literal(void)
{
    if (TEST(NUM)) {
        next_token();
    }
    else if (TEST(CHARA)) {
        next_token();
    }
    else if (TEST(STRING)) {
        next_token();
    }
    else {
        syn_err(EXPECTED_LITERAL_OR_EXPR, ERROR, OTHER, NULL);
    }
}



/*
    <block>	 ->	lbraces <subprogram> rbraces
*/
void block(void)
{
    if (!match(LBRACES))
        recovery(true, EXPECTED_LBRACES, ERROR);  // 因为可能的情况太多，这里就不罗列
                                                 // follow 集了，直接报丢失。
                                 
    subprogram();

    if (!match(RBRACES))
        recovery(true, EXPECTED_RBRACES, ERROR); // 因为可能的情况太多，这里就不罗列
                                                 // follow 集了，直接报丢失。
}

/*
<subprogram>	->	<local_decl> <subprogram>
                |   <statement> <subprogram>
                |   <block>  <subprogram>
                |   ε
*/

void subprogram(void)
{
    if (TEST(INT) OR(CHAR) OR(VOID) OR(EXTERN)) { 
        local_decl();
        subprogram();
    }
    else if (STATEMENT_FIRST) { //语句
        statement();
        subprogram();
    }
    else if (TEST(LBRACES)) {
        block();
        subprogram();
    }
}

/*
<subprogram_in_switch>	->	<statement> <subprogram_in_switch>
					    |   <block>  <subprogram_in_switch>    
					    |   ε
*/
void subprogram_in_switch(void)
{
    if (STATEMENT_FIRST) { //语句
        statement();
        subprogram_in_switch();
    }
    else if (TEST(LBRACES)) {
        block();
        subprogram_in_switch();
    } else if(TEST(INT) OR(CHAR) OR(VOID) OR(EXTERN)) { 
        // 报错  need statement, not declaration
        syn_err(NEED_STATEMENT,  ERROR, OTHER, NULL);
        local_decl(); // 经测试，这样可以跳过错误代码，不影响后面的解析
        subprogram_in_switch();
    } 

}
/*
<expr_stat> -> <expr> semico
             | semico
*/
void expr_stat(void)
{
    if (EXPR_FIRST)
        expr();

    if (!match(SEMICO))
        recovery(EXPR_STAT_FOLLOW, EXPECTED_SEMICOLON, ERROR);
}



/*
<statement> -> <expr_stat>
            | <while_stat>
            | <for_stat>
            | <do_while_stat>
            | <if_stat>
            | <switch_stat>
            | <break_stat>
            | <continue_stat>
            | <return_stat>

*/

void statement(void)
{
    switch (token_g) {
        case WHILE:
            while_stat();
            break;

        case FOR:
            for_stat();
            break;

        case DO:
            do_while_stat();
            break;

        case IF:
            if_stat();
            break;

        case SWITCH:
            switch_stat();
            break;

        case BREAK: /*  <break_stat> -> break semico */             
            next_token();
            if (!match(SEMICO))
                recovery(BREAK_STAT_FOLLOW, EXPECTED_SEMICOLON, ERROR); 

            break;

        case CONTINUE: /* <continue_stat> -> continue semico */                    
            next_token();
            if (!match(SEMICO))
                recovery(CONTINUE_STAT_FOLLOW, EXPECTED_SEMICOLON, ERROR); 

            break;

        case RETURN: /* <return_stat> -> return <expr_stat> */
            next_token();
            expr_stat();
            break;

        default:
            expr_stat();
            break;
    }
}

/*

 <while_stat> -> while lparen <expr> rparen <block>
              |  while lparen <expr> rparen <statement>
*/

void while_stat(void)
{
    match(WHILE);
    if (!match(LPAREN))
        recovery(EXPR_FIRST, EXPECTED_LPAREN, ERROR); 

    expr();

    if (!match(RPAREN))
        recovery(TEST(LBRACES)|| STATEMENT_FIRST, EXPECTED_RPAREN, ERROR);

    if (TEST(LBRACES)) { // 如果遗漏了 '{' , 会产生大片错误。gcc 也是如此
        block();
    } else {
        statement(); 
    }
}

/*
<do_while_stat> -> do <block>  while lparen <expr> rparen semico
                 | do <statement> while lparen <expr> rparen semico

*/

void do_while_stat(void)
{
    match(DO);
    if (TEST(LBRACES)) {
        block();
    } else {
        statement();
    }

    if (!match(WHILE))
        recovery(TEST(LPAREN), EXPECTED_WHILE, ERROR);

    if (!match(LPAREN))
        recovery(EXPR_FIRST, EXPECTED_LPAREN, ERROR);

    expr();

    if (!match(RPAREN))
        recovery(TEST(SEMICO), EXPECTED_RPAREN, ERROR);

    if (!match(SEMICO)) // 因为可能的情况太多，这里就不罗列 follow
                        // 集了，直接报丢失。
        recovery(true, EXPECTED_SEMICOLON, ERROR);
}

/*
<for_stat> 	-> 	for lparen <for_init>  <for_cond>  <for_iter> rparen  <block>
             |	for lparen <for_init>  <for_cond>  <for_iter> rparen <statement>

*/

void for_stat(void)
{
    match(FOR);
    if (!match(LPAREN))
        recovery(TYPE_FIRST || EXPR_FIRST || TEST(SEMICO), EXPECTED_LPAREN,
                 ERROR);

    for_init(); // 初始语句
    for_cond(); // 循环条件
    for_iter(); // 迭代语句

    if (!match(RPAREN))
        recovery(TEST(LBRACES)|| STATEMENT_FIRST, EXPECTED_RPAREN, ERROR);

    if (TEST(LBRACES)) {
        block();
    } else {
        statement();
    }
}
/*
<decl_head>    ->   ident | mul ident 
<for_init>     ->  <type> <decl_head> <var_decl_tail>
                |  <expr_stat>
*/
void for_init(void)
{
    if (TYPE_FIRST) {
        symbol_e my_type = type();
        char name[MAX_ID_LEN + 1] = {0};
        bool is_ptr = false;

        if (match(MUL)) { 
            is_ptr = true;
        }
        if (TEST(ID)) {
            get_id(name);
            next_token();
        } else {
            recovery(DECL_HEAD_FOLLOW, EXPECTED_ID,
                     ERROR); // error: expected identifier
        }
        var_decl_tail(false, my_type, is_ptr, name);
    } else {
        expr_stat();
    }
}

/*

<for_cond> ->  <expr_stat>
*/

void for_cond(void)
{ 
    expr_stat(); 
}

/*

<for_iter> ->  <expr> | ε
*/
void for_iter(void)
{
    if (EXPR_FIRST)
        expr();
}

/*
<if_stat> -> if lparen <expr> rparen <block> <else_stat>
           | if lparen <expr> rparen <statement> <else_stat>
*/

void if_stat(void)
{
    match(IF);
    if (!match(LPAREN))
        recovery(EXPR_FIRST, EXPECTED_LPAREN, ERROR);

    expr();

    if (!match(RPAREN)){
        recovery(STATEMENT_FIRST OR(LBRACES), EXPECTED_RPAREN,
                 ERROR); 
    } 

    if (TEST(LBRACES)) {
        block();
    } else {
        statement();
    }

    else_stat();
}



/*

<else_stat> -> else <block>
             | else <statement>
             | ε

*/
void else_stat(void)
{
    if (match(ELSE)) {
        if (TEST(LBRACES)) {
            block();
        } else {
            statement();
        }
    }
}

/*

<switch_stat>	-> 	switch lparen <expr> rparen lbraces <case_stat> rbraces

*/

void switch_stat(void)
{
    match(SWITCH);
    if (!match(LPAREN))
        recovery(EXPR_FIRST, EXPECTED_LPAREN, ERROR);
    
    expr();

    if (!match(RPAREN))
        recovery(TEST(LBRACES), EXPECTED_RPAREN, ERROR);
    if (!match(LBRACES))
        recovery(TEST(CASE) OR(DEFAULT), EXPECTED_LBRACES, ERROR);

    case_stat();

    if (!match(RBRACES))
        recovery(SWITCH_STAT_FOLLOW, EXPECTED_RBRACES, ERROR);
}



/*
    <case_stat> 	-> 	case <case_label> colon <subprogram_in_switch> <case_stat> 
                    |   default  colon <subprogram_in_switch> <case_stat> 
                    |   ε 
*/
void case_stat(void)
{
    if (match(CASE)) {
        case_label();

        if (!match(COLON))
        recovery(STATEMENT_FIRST OR(LBRACES)OR(RBRACES)OR(CASE)OR(DEFAULT), 
                EXPECTED_COLON, ERROR);
        /*
            不能有 	<local_decl>  gcc 报错 
            error: a label can only be part of a statement 
            and a declaration is not a statement     
        */
        subprogram_in_switch(); 
        case_stat(); // 递归
    } else if (match(DEFAULT)) {
        if (!match(COLON))
            recovery(STATEMENT_FIRST OR(LBRACES)OR(RBRACES)OR(CASE)OR(DEFAULT), 
                    EXPECTED_COLON, ERROR);

        subprogram_in_switch();
        case_stat(); // 递归
    } 
}

// <case_label>	->	num | chara
void case_label(void) 
{ 
    if(TEST(NUM)OR(CHARA))
        literal(); 
    else{ 
        if (TEST(COLON)) {
             syn_err(EXPECTED_LITERAL, ERROR, OTHER, NULL);
        }
        else {
            // gcc: case label does not reduce to an integer constant
            syn_err(CASE_LABEL_NOT_INT_CONSTANT, ERROR, OTHER, NULL);
            next_token();
        }
    }
}
